/* $Header: cpf_det.c,v 2.2 01/10/02 10:26:04 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* INCLUDE FILE NAME:  cpf_det.c                                       */
/* ==================                                                  */
/*                                                                     */
/* Author:  Bob Cook                                                   */
/*                                                                     */
/* COMMENT: CPF Detector functions.                                    */
/*                                                                     */
/***********************************************************************/

/*****************************/
/*  PROJECT INCLUDE FILES    */
/*****************************/

#include <typedefs.h>
#include <i_op.h>
#include <iomap.h>
#include <error.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>
#include <detector.h>
#include <p_status.h>
#include <det_ui.h>
#include <exception.h>
#include <err_handler.h>
#include <glp.h>
#include <pcb_defs.h>

#include <method.h>
#include <meth_config.h>
#include <mio.h>
#include <cmd_set.h>
#include <hostutil.h>
#include <p_ui.h>


/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

/*****************************/
/*   STATIC PROTOTYPES       */
/*****************************/

static UI_ERR SetRTTOEMXtrlValue( POSITION position,  INT32 value , BIT8 wkf_flag );

static void RTTSetOxMCtl ( POSITION position, BIT8 channel, INT32 value );

/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/

extern void DetectorIOTransfer(void);

extern const BIT8  OEMGas1PresLabel[9];
extern const BIT8  OEMGas2PresLabel[9];
extern const BIT8  OEMGas3PresLabel[9];
extern const BIT8  OEMGas1FlowLabel[9];
extern const BIT8  OEMGas2FlowLabel[9];
extern const BIT8  OEMGas3FlowLabel[9];

extern const BIT8  OEMCtl1Label[13];
extern const BIT8  OEMCtl2Label[13];
extern const BIT8  OEMCtl3Label[13];
extern const BIT8  OEMCtl4Label[13];
extern const BIT8  OEMCtl5Label[13];
extern const BIT8  OEMDataOutLabel[13];
extern const BIT8  OEMDataInLabel[13];
extern const BIT8  OEMDiag1Label[13];
extern const BIT8  OEMDiag2Label[13];

#define oldg   pDiag->OldGain
#define mult   pDiag->mult
#define dvdr   pDiag->dvdr
#define  ofs   pDiag->offset

extern const BIT8  OEM_DET_MODE_CFG_CNT;
extern const BIT8  OEM_DET_LABEL_CFG_CNT;

/*   OEM_DET_MODE_CFG_CNT    = # of OEM DET gases to be "gccw" cfg chkd  ; each gas has bit_mapped error bit */
/*   OEM_DET_LABEL_CFG_CNT   = # of OEM DET labels to be "gccw" cfg chkd ; each gas has bit_mapped error bit */

#define MODZ      OEM_DET_MODE_CFG_CNT
#define LBLZ      OEM_DET_LABEL_CFG_CNT

/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/

INT32  GetOEMDiagValu ( POSITION pos, BIT8 ch )
{
   OEM_DIAG_TYPE     *pDiag;
   U_INT16            idata;
   U_INT16            *optr;

   switch ( 2*(BIT8)pos + ch )
   {
      default:
      case 1 :
                pDiag = &FDDiag1 ;
                idata = Det_Diaga_Rdg;
                optr  = &FDDiag1Fltr;
                break ;

      case 2 :
                pDiag = &FDDiag2 ;
                idata = Det_Diagb_Rdg;
                optr  = &FDDiag2Fltr;
                break ;

      case 3 :
                pDiag = &BDDiag1 ;
                idata = Det_Diagc_Rdg;
                optr  = &BDDiag1Fltr;
                break ;

      case 4 :
                pDiag = &BDDiag2 ;
                idata = Det_Diagd_Rdg;
                optr  = &BDDiag2Fltr;
                break ;
   };

   *optr =  ((*optr)*oldg + (idata)*(256-oldg) ) /256;

   return ( mult*((*optr-ofs)/dvdr) );

}

BIT8  *GetDetGasLabel( POSITION pos, BIT8 gas )
{
   BIT8           *labl;

   switch ( gas )
   {
      default:
      case 1:
              labl = (pos == FRONT ) ? FDGas1.label : BDGas1.label;
              break;
      case 2:
              labl = (pos == FRONT ) ? FDGas2.label : BDGas2.label;
              break;
      case 3:
              labl = (pos == FRONT ) ? FDGas3.label : BDGas3.label;
              break;
   }
   return labl ;
}

OEM_GAS_STATUS  GetOEMGasStatus( pDETECTOR_STATUS status, BIT8 gas )
{
   BIT8           *label;

   if ( 0 == GetDetMaxPres( status, gas ) )
   {
      return NOT_USED;
   }

   label = GetDetGasLabel((status == pFRONT_DETECTOR) ? FRONT:BACK , gas);

   if ( *label == 1 ) return NOT_USED ;

   if ( 0 == GetMaxDetGasFlow( status, gas ) )
   {
      return PRES ;
   }
   else
   {
      return FLOW;
   }
}

/***********************************************************************/
/* FUNCTION: Presence Functions                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determines if CPF label is present                         */
/*    presence is determined by a non-zero value in the first byte     */
/*    of the label.                                                    */
/*                                                                     */
/* RETURNED VALUE: TRUE or FALSE                                       */
/*                                                                     */
/***********************************************************************/

BIT8  GetCPFDetPneuPresence( POSITION position )
{
   if (position==FRONT)
   {
      return (FDCPF);
   }
   else
   {
      return (BDCPF);
   }
}


BIT8  GetCPFDetTitlePresence( POSITION position )
{
   switch ( GetDetectorType(position))
   {
      case OEM_AIB:
      case OEM_FID:
            return   FALSE;
   };

   if (position==FRONT)
   {
      return ( FDName[0] != 0 ) ? TRUE : FALSE;
   }
   else
   {
      return ( BDName[0] != 0 ) ? TRUE : FALSE;
   }
}

BIT8  GetCPFDetGasPresence( POSITION position, BIT8 gas_num )
{
   return (*GetDetGasLabel(position,gas_num) != 0)? TRUE:FALSE ;
}


BIT8  GetCtlPresence( POSITION position, BIT8 channel ,BIT8 valu )
{
   switch ( channel )
   {
      case 1:
         if (position==FRONT)
         {
            return  ( FDCtl1.label[0] != valu ) ? TRUE : FALSE;
         }
         else
         {
            return  ( BDCtl1.label[0] != valu ) ? TRUE : FALSE;
         }
      case 2:
         if (position==FRONT)
         {
            return  ( FDCtl2.label[0] != valu ) ? TRUE : FALSE;
         }
         else
         {
            return  ( BDCtl2.label[0] != valu ) ? TRUE : FALSE;
         }
      case 3:
         if (position==FRONT)
         {
            return  ( FDCtl3.label[0] != valu ) ? TRUE : FALSE;
         }
         else
         {
            return  ( BDCtl3.label[0] != valu ) ? TRUE : FALSE;
         }
      case 4:
         if (position==FRONT)
         {
            return  ( FDCtl4.label[0] != valu ) ? TRUE : FALSE;
         }
         else
         {
            return  ( BDCtl4.label[0] != valu ) ? TRUE : FALSE;
         }
      case 5:
        if (position==FRONT)
        {
            return  ( FDCtrl5.label[0] != valu ) ? TRUE : FALSE;
        }
        else
        {
            return  ( BDCtrl5.label[0] != valu ) ? TRUE : FALSE;
        }
      case 6:
        if (position==FRONT)
        {
            return  ( FDXtrl6.label[0] != valu ) ? TRUE : FALSE;
        }
        else
        {
            return  ( BDXtrl6.label[0] != valu ) ? TRUE : FALSE;
        }
      case 7:
        if (position==FRONT)
        {
            return  ( FDXtrl7.label[0] != valu ) ? TRUE : FALSE;
        }
        else
        {
            return  ( BDXtrl7.label[0] != valu ) ? TRUE : FALSE;
        }
      case 8:
            return FALSE ;  /* b/c 8=True <==> label6=label7 */
      case 9:
        if (position==FRONT)
        {
            return  ( FDDiag1.label[0] != valu ) ? TRUE : FALSE;
        }
        else
        {
            return  ( BDDiag1.label[0] != valu ) ? TRUE : FALSE;
        }
      case 10:
        if (position==FRONT)
        {
            return  ( FDDiag2.label[0] != valu ) ? TRUE : FALSE;
        }
        else
        {
            return  ( BDDiag2.label[0] != valu ) ? TRUE : FALSE;
        }
      default:
            return FALSE ;
   }
}

BIT8  GetOEMCtlPresence( POSITION position, BIT8 channel )
{
   return GetCtlPresence(position,channel,1);    /* label[0]=01H will SUPPRESS the control */
}

BIT8  GetCPFCtlPresence( POSITION position, BIT8 channel )
{
   switch ( GetDetectorType(position))
   {
      case OEM_AIB:
      case OEM_FID:
            return   FALSE;
   };

   if ( OIMPresence[ (BIT8)position ] == 0 ) return FALSE ;
   return GetCtlPresence(position,channel,0);    /* label[0]=00H will SUPPRESS the control */
}

BIT8  GetCPFOIMPresence( POSITION position )
{
   /* get CPF's OIM board present information */
   return OIMPresence[ (BIT8)position ];
}


/***********************************************************************/
/* FUNCTION: GetCPFDetTitle                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Returns pointer to the title of the CPF Det                */
/*                                                                     */
/***********************************************************************/

BIT8  *GetCPFDetTitle( POSITION position )
{
     return (position==FRONT) ? FDName : BDName;
}

/***********************************************************************/
/* FUNCTION: GetCPFGasLabel                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Returns pointer to gas label of the CPF or OEM detector    */
/*                                                                     */
/***********************************************************************/

BIT8  *GetCPFGasLabel( POSITION position, BIT8 gas_num )
{

   pDETECTOR_STATUS status;
   BIT8           *label;

   status = (position==FRONT) ? &Inst_Status.Pneu.Frnt_Detector : &Inst_Status.Pneu.Back_Detector ;

   label = GetDetGasLabel(position, gas_num );

   if ( ( GetDetType( status ) != EPC_OEM ) || ( *label != 0 ) ) return label ;

   switch ( gas_num )  /* here on to get default OEM gas label */
   {
      default:
      case 1:
         label = (BIT8*)(( status->Gas_1.FRIT_MAX_FLOW == 0) ? OEMGas1PresLabel : OEMGas1FlowLabel);
         break ;
      case 2:
         label = (BIT8*)(( status->Gas_2.FRIT_MAX_FLOW == 0) ? OEMGas2PresLabel : OEMGas2FlowLabel);
         break ;
      case 3:
         label = (BIT8*)(( status->Gas_3.FRIT_MAX_FLOW == 0) ? OEMGas3PresLabel : OEMGas3FlowLabel);
         break ;
   }
   return label ;
}

/***********************************************************************/
/* FUNCTION: GetCPFCtlLabel                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Returns pointer to the control label of the CPF detector   */
/*                                                                     */
/***********************************************************************/

BIT8  *GetCPFCtlLabel( POSITION position, BIT8 channel )
{

   pDETECTOR_STATUS status;
   BIT8             *label;

   status = (position==FRONT) ? &Inst_Status.Pneu.Frnt_Detector : &Inst_Status.Pneu.Back_Detector ;

   switch ( channel )
   {
      default:
      case 1:
              label = (position==FRONT) ? FDCtl1.label : BDCtl1.label;
              break ;
      case 2:
              label = (position==FRONT) ? FDCtl2.label : BDCtl2.label;
              break ;
      case 3:
              label = (position==FRONT) ? FDCtl3.label : BDCtl3.label;
              break ;
      case 4:
              label = (position==FRONT) ? FDCtl4.label : BDCtl4.label;
              break ;
      case 5:
              label = (position==FRONT) ? FDCtrl5.label : BDCtrl5.label;
              break ;
      case 6:
              label = (position==FRONT) ? FDXtrl6.label : BDXtrl6.label;
              break ;
      case 7:
              label = (position==FRONT) ? FDXtrl7.label : BDXtrl7.label;
              break ;
      case 9:
              label = (position==FRONT) ? FDDiag1.label : BDDiag1.label;
              break ;
      case 10:
              label = (position==FRONT) ? FDDiag2.label : BDDiag2.label;
              break ;
   }
   if ( ( GetDetType( status ) != EPC_OEM ) || ( *label != 0 ) ) return label ;

   switch ( channel )  /* here on to get default OEM control label */
   {
      default:
      case  1:
              label = (BIT8*)OEMCtl1Label ;
              break ;
      case  2:
              label = (BIT8*)OEMCtl2Label ;
              break ;
      case  3:
              label = (BIT8*)OEMCtl3Label ;
              break ;
      case  4:
              label = (BIT8*)OEMCtl4Label ;
              break ;
      case  5:
              label = (BIT8*)OEMCtl5Label ;
              break ;
      case  6:
              label = (BIT8*)OEMDataInLabel;
              break ;
      case  7:
              label = (BIT8*)OEMDataOutLabel;
              break ;
      case  9:
              label = (BIT8*)OEMDiag1Label;
              break ;
      case 10:
              label = (BIT8*)OEMDiag2Label;
              break ;
   }
   return label ;
}


/***********************************************************************/
/* FUNCTION: GetCPFCtlFormat                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Returns format associated with a given control channel     */
/*                                                                     */
/***********************************************************************/

BIT8 GetCPFCtlFormat( POSITION position, BIT8 channel )
{
   switch ( channel )
   {
      default:
      case 1:
              return (position==FRONT) ? FDCtl1.format : BDCtl1.format;
      case 2:
              return (position==FRONT) ? FDCtl2.format : BDCtl2.format;
      case 3:
              return (position==FRONT) ? FDCtl3.format : BDCtl3.format;
      case 4:
              return (position==FRONT) ? FDCtl4.format : BDCtl4.format;
   }
}

/***********************************************************************/
/* FUNCTION: GetCPFCtlNumBits                                          */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Returns number of bits associated with a given control     */
/*           channel.                                                  */
/*                                                                     */
/***********************************************************************/

BIT8 GetCPFCtlNumBits( POSITION position, BIT8 channel )
{
   switch ( channel )
   {
      default:
      case 1:
              return (position==FRONT) ? FDCtl1.bits : BDCtl1.bits;
      case 2:
              return (position==FRONT) ? FDCtl2.bits : BDCtl2.bits;
      case 3:
              return (position==FRONT) ? FDCtl3.bits : BDCtl3.bits;
      case 4:
              return (position==FRONT) ? FDCtl4.bits : BDCtl4.bits;
   }
}


/***********************************************************************/
/* FUNCTION: MinCPFCtlValue   MaxCPFCtlValue                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determine min and max control values for OIM module        */
/*                                                                     */
/* RETURNED VALUE: Min and Max Control Values                          */
/*                                                                     */
/***********************************************************************/

INT32 MinCPFCtlValue( POSITION position, BIT8 channel )
{
   (void)  position;
   (void)  channel;
   return 0;
}

INT32 MaxCPFCtlValue( POSITION position, BIT8 channel )
{
   if(position == FRONT)
   {
      switch(channel)
      {
         default:
         case 1:
            return ( ((U_INT32)1) << FDCtl1.bits ) - 1;
         case 2:
            return ( ((U_INT32)1) << FDCtl2.bits ) - 1;
         case 3:
            return ( ((U_INT32)1) << FDCtl3.bits ) - 1;
         case 4:
            return ( ((U_INT32)1) << FDCtl4.bits ) - 1;
      }
   }
   else
   {
      switch(channel)
      {
         default:
         case 1:
            return (((U_INT32)1) << BDCtl1.bits) - 1;
         case 2:
            return (((U_INT32)1) << BDCtl2.bits) - 1;
         case 3:
            return (((U_INT32)1) << BDCtl3.bits) - 1;
         case 4:
            return (((U_INT32)1) << BDCtl4.bits) - 1;
      }
   }
}

UI_ERR CheckOEMCtlOnOff( POSITION position, BIT8 channel, ON_OFF value )
{
   if( value != OFF && value != ON) return INVALID_PARAM;

   if ( GetOEMCtlPresence( position,channel) == FALSE  )  return NOT_ALLOWED;

   return OK;

}


/***********************************************************************/
/* FUNCTION: CheckCPFCtlOnOff                                          */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determine if the control values for the OIM module are     */
/*            within a valid range.                                    */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/***********************************************************************/

UI_ERR CheckCPFCtlOnOff( POSITION position, BIT8 channel, ON_OFF value )
{
   if ( MaxCPFCtlValue(position, channel) == 0 )
   {
      /* no bits associated with this control */
      return INVALID_PARAM;
   }

   if( value == OFF || value == ON)
   {
      return OK;
   }
   else
   {
      return INVALID_PARAM;
   }

}

/***********************************************************************/
/* FUNCTION: CheckCPFCtlValue                                          */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determine if the control values for the OIM module are     */
/*            within a valid range.                                    */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/***********************************************************************/

UI_ERR CheckCPFCtlValue( POSITION position, BIT8 channel, INT32 value )
{
INT32 max;
U_INT16 format;

   switch (channel)
   {
   default:
   case 1:
      format = (position == FRONT) ? FDCtl1.format : BDCtl1.format;
      break;
   case 2:
      format = (position == FRONT) ? FDCtl2.format : BDCtl2.format;
      break;
   case 3:
      format = (position == FRONT) ? FDCtl3.format : BDCtl3.format;
      break;
   case 4:
      format = (position == FRONT) ? FDCtl4.format : BDCtl4.format;
      break;
   }
   switch (format)
   {
   case FRMT_ON_OFF:
      /* ignore parameter or on/off format */
      return OK;
   case FRMT_NUMERIC:
      if ( value < MinCPFCtlValue(position, channel))
      {
         return PARAM_TOO_SMALL;
      }

      max =  MaxCPFCtlValue(position, channel);
      if ( max == 0 )
      {
         /* no bits associated with this control */
         return INVALID_PARAM;
      }

      if ( value > max)
      {
         return PARAM_TOO_LARGE;
      }

      return OK;
   default:
      return OK;
   }
}

/***********************************************************************/
/* FUNCTION: GetCPFCtlOnOff                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Get the current workfile ON or OFF state of the given      */
/*            OIM module's control channel.                            */
/*                                                                     */
/* RETURNED VALUE:  control value                                      */
/*                                                                     */
/***********************************************************************/

ON_OFF GetCPFCtlOnOff( POSITION position, BIT8 channel )
{
   if(position == FRONT)
   {
      switch (channel)
      {
         default:
         case 1:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              FDCtl1.mask) >> FDCtl1.shift == 0 )? OFF:ON;
         case 2:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              FDCtl2.mask) >> FDCtl2.shift == 0 )? OFF:ON;
         case 3:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              FDCtl3.mask) >> FDCtl3.shift == 0 )? OFF:ON;
         case 4:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              FDCtl4.mask) >> FDCtl4.shift == 0 )? OFF:ON;
      }
   }
   else
   {
      switch (channel)
      {
         default:
         case 1:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              BDCtl1.mask) >> BDCtl1.shift == 0 )? OFF:ON;
         case 2:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              BDCtl2.mask) >> BDCtl2.shift == 0 )? OFF:ON;
         case 3:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              BDCtl3.mask) >> BDCtl3.shift == 0 )? OFF:ON;
         case 4:
            return ( ((Active_Wkfile.det_cpf_ctl[position].on_off) &
                              BDCtl4.mask) >> BDCtl4.shift == 0 )? OFF:ON;
      }
   }
}

/***********************************************************************/
/* FUNCTION: GetCPFCtlValue                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Get the current workfile value of the given OIM module's   */
/*            control channel.                                         */
/*                                                                     */
/* RETURNED VALUE:  control value                                      */
/*                                                                     */
/***********************************************************************/

U_INT16 GetCPFCtlValue( POSITION position, BIT8 channel )
{
   if(position == FRONT)
   {
      switch (channel)
      {
         default:
         case 1:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & FDCtl1.mask) >> FDCtl1.shift;
         case 2:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & FDCtl2.mask) >> FDCtl2.shift;
         case 3:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & FDCtl3.mask) >> FDCtl3.shift;
         case 4:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & FDCtl4.mask) >> FDCtl4.shift;
      }
   }
   else
   {
      switch (channel)
      {
         default:
         case 1:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & BDCtl1.mask) >> BDCtl1.shift;
         case 2:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & BDCtl2.mask) >> BDCtl2.shift;
         case 3:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & BDCtl3.mask) >> BDCtl3.shift;
         case 4:
            return ((Active_Wkfile.det_cpf_ctl[position].value) & BDCtl4.mask) >> BDCtl4.shift;
      }
   }
}

/***********************************************************************/
/* FUNCTION: SetCPFCtlOnOff                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Sets ON or OFF parameter in the workfile and active        */
/*         value for the given OIM module's control channel.           */
/*                                                                     */
/* RETURNED VALUE:  Error code                                         */
/*                                                                     */
/***********************************************************************/


UI_ERR SetCPFCtlOnOff( POSITION position, BIT8 channel, ON_OFF value )
{
   UI_ERR  error;
   U_INT16 mask;
   BIT8    shift;
   BIT8    format;
   BIT8   *label;

   error = CheckCPFCtlOnOff(position, channel, value );
   if( (error == INVALID_PARAM) && (value == OFF) )
   {
      /* To keep chemstation happy:   */
      /*    this channel is not in use, a value of 0 is allowed */
      /*    but don't do anything. */
      error = OK;
      return error;
   }
   if(error == OK)
   {
      switch ( channel )
      {
         default:
         case 1: mask  = (position==FRONT) ? FDCtl1.mask  : BDCtl1.mask;
                 shift = (position==FRONT) ? FDCtl1.shift : BDCtl1.shift;
                 label = (position==FRONT) ? FDCtl1.label : BDCtl1.label;
                 format =(position==FRONT) ? FDCtl1.format : BDCtl1.format;
                 break;

         case 2: mask  = (position==FRONT) ? FDCtl2.mask  : BDCtl2.mask;
                 shift = (position==FRONT) ? FDCtl2.shift : BDCtl2.shift;
                 label = (position==FRONT) ? FDCtl2.label : BDCtl2.label;
                 format =(position==FRONT) ? FDCtl2.format : BDCtl2.format;
                 break;

         case 3: mask  = (position==FRONT) ? FDCtl3.mask  : BDCtl3.mask;
                 shift = (position==FRONT) ? FDCtl3.shift : BDCtl3.shift;
                 label = (position==FRONT) ? FDCtl3.label : BDCtl3.label;
                 format =(position==FRONT) ? FDCtl3.format : BDCtl3.format;
                 break;

         case 4: mask  = (position==FRONT) ? FDCtl4.mask  : BDCtl4.mask;
                 shift = (position==FRONT) ? FDCtl4.shift : BDCtl4.shift;
                 label = (position==FRONT) ? FDCtl4.label : BDCtl4.label;
                 format =(position==FRONT) ? FDCtl4.format : BDCtl4.format;
                 break;
      }

      if(value == OFF)
      {
          /* reset proper bits */
         INTERRUPTS_OFF
            Active_Wkfile.det_cpf_ctl[position].on_off =
               Active_Wkfile.det_cpf_ctl[position].on_off & ~mask; /* set wkfile */
            DetCpfCtl[position].on_off =
               DetCpfCtl[position].on_off & ~mask; /* set working copy */
            SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                      position );     /* set board */
         INTERRUPTS_ON
         /* log setpoint change and set parameter modified flag */
         if (position==FRONT)
         {
             LogSetptChange(F_DET_CONTROL_OFF,(INT32)label,0);
         }
         else
         {
            LogSetptChange(B_DET_CONTROL_OFF,(INT32)label,0);
         }
      }
      else
      {
         /* value = ON, so turn on bits */

         if (format == FRMT_ON_OFF)
         {
            /* make sure value is all 1s for ON_OFF format */
            /*   so bit will come on */
            (void)SetCPFCtlValue( position, channel,
                     (INT32)MaxCPFCtlValue(position,channel) );
         }

         /* Numeric format so set value */

         INTERRUPTS_OFF
         Active_Wkfile.det_cpf_ctl[position].on_off =
               (Active_Wkfile.det_cpf_ctl[position].on_off & ~mask) |
               ( ((U_INT16)MaxCPFCtlValue(position,channel)<<shift) & mask ); /*set workfile*/
         DetCpfCtl[position].on_off =
               (DetCpfCtl[position].on_off & ~mask) |
               ( ((U_INT16)MaxCPFCtlValue(position,channel)<<shift) & mask );  /*set work cpy*/
         SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                      position );     /* set board */
         INTERRUPTS_ON

         /* log setpoint change and set parameter modified flag */
         (position==FRONT) ? LogSetptChange(F_DET_CONTROL_ON,(INT32)label,0) :
                             LogSetptChange(B_DET_CONTROL_ON,(INT32)label,0);
      }
   }
   return error;
}


/***********************************************************************/
/* FUNCTION: SetCPFCtlValue                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Set the workfile and active value for the given OIM        */
/*        module's control channel.                                    */
/*                                                                     */
/* RETURNED VALUE:  Error code                                         */
/*                                                                     */
/***********************************************************************/

UI_ERR SetCPFCtlValue( POSITION position, BIT8 channel, INT32 value )
{
   UI_ERR  error;
   U_INT16 mask;
   BIT8    shift;
   BIT8    format;
   BIT8   *label;

   error = CheckCPFCtlValue(position, channel, value );
   if( (error == INVALID_PARAM) && (value == 0) )
   {
      /* To keep chemstation happy:   */
      /*    this channel is not in use, a value of 0 is allowed */
      /*    but don't do anything. */
      error = OK;
      return error;
   }
   if(error == OK)
   {
      switch ( channel )
      {
         default:
         case 1: mask  = (position==FRONT) ? FDCtl1.mask  : BDCtl1.mask;
                 shift = (position==FRONT) ? FDCtl1.shift : BDCtl1.shift;
                 label = (position==FRONT) ? FDCtl1.label : BDCtl1.label;
                 format =(position==FRONT) ? FDCtl1.format : BDCtl1.format;
                 break;

         case 2: mask  = (position==FRONT) ? FDCtl2.mask  : BDCtl2.mask;
                 shift = (position==FRONT) ? FDCtl2.shift : BDCtl2.shift;
                 label = (position==FRONT) ? FDCtl2.label : BDCtl2.label;
                 format =(position==FRONT) ? FDCtl2.format : BDCtl2.format;
                 break;

         case 3: mask  = (position==FRONT) ? FDCtl3.mask  : BDCtl3.mask;
                 shift = (position==FRONT) ? FDCtl3.shift : BDCtl3.shift;
                 label = (position==FRONT) ? FDCtl3.label : BDCtl3.label;
                 format =(position==FRONT) ? FDCtl3.format : BDCtl3.format;
                 break;

         case 4: mask  = (position==FRONT) ? FDCtl4.mask  : BDCtl4.mask;
                 shift = (position==FRONT) ? FDCtl4.shift : BDCtl4.shift;
                 label = (position==FRONT) ? FDCtl4.label : BDCtl4.label;
                 format =(position==FRONT) ? FDCtl4.format : BDCtl4.format;
                 break;
      }

      if(format == FRMT_ON_OFF)
      {
         /* for ON/OFF format always set value to all 1s */
         value = (INT32)MaxCPFCtlValue(position,channel);
      }

      INTERRUPTS_OFF
      Active_Wkfile.det_cpf_ctl[position].value =
            (Active_Wkfile.det_cpf_ctl[position].value & ~mask) |
            ( (((U_INT16)value)<<shift) & mask );  /* set workfile */
      DetCpfCtl[position].value =
            (DetCpfCtl[position].value & ~mask) |
            ( (((U_INT16)value)<<shift) & mask );  /* set working copy */
      SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                   position );     /* set board */
      INTERRUPTS_ON

      /* if format is ON/OFF, the setpt is logged under SetCPFCtlOnOff function;
          so don't log it here */
      if(format != FRMT_ON_OFF)
      {
         if (position==FRONT)
         {
            LogSetptChange(F_DET_CONTROL,(INT32)label,value);
         }
         else
         {
            LogSetptChange(B_DET_CONTROL,(INT32)label,value);
         }
      }
   }
   return error;
}

/***********************************************************************/
/* FUNCTION: CPFCtlBdOnOff                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Enable or Disable all of the OIM boards outputs.           */
/*                                                                     */
/* RETURNED VALUE:  none                                               */
/*                                                                     */
/***********************************************************************/

void CPFCtlBdOnOff( POSITION position, ON_OFF on_off )
{
   if(position == FRONT)
   {
      DISCRETE_OUT1 = DiscreteOut1_Image = (on_off == OFF) ?
         (DiscreteOut1_Image & CPFA_BD_OFF) : (DiscreteOut1_Image | CPFA_BD_ON);
   }
   else
   {
      DISCRETE_OUT1 = DiscreteOut1_Image = (on_off == OFF) ?
         (DiscreteOut1_Image & CPFB_BD_OFF) : (DiscreteOut1_Image | CPFB_BD_ON);
   }
}

/***********************************************************************/
/* FUNCTION: UpdateCPFCtlValues                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  This functions sets the initial values for the CPF's      */
/*           OIM control values.                                       */
/*                                                                     */
/* RETURNED VALUE:  None.                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void UpdateCPFCtlValues (void)
{
   POSITION position;

#if 0
   /* Set the current setpoints to the values in the workfile.  */

   position = FRONT;

   if (GetCPFOIMPresence( position ))
   {
    INTERRUPTS_OFF
      DetCpfCtl[position].on_off = Active_Wkfile.det_cpf_ctl[position].on_off;
      DetCpfCtl[position].value = Active_Wkfile.det_cpf_ctl[position].value;
      SetDetControlSetpts(DetCpfCtl[position].on_off&DetCpfCtl[position].value,
                                position );     /* set board */
    INTERRUPTS_ON
   }

   position = BACK;

   if (GetCPFOIMPresence( position ))
   {
    INTERRUPTS_OFF
      DetCpfCtl[position].on_off = Active_Wkfile.det_cpf_ctl[position].on_off;
      DetCpfCtl[position].value = Active_Wkfile.det_cpf_ctl[position].value;
      SetDetControlSetpts(DetCpfCtl[position].on_off&DetCpfCtl[position].value,
                                position );     /* set board */
    INTERRUPTS_ON
   }
#endif

   for( position = FRONT; position <= BACK; position++ )
   {
      if (GetCPFOIMPresence( position ))
      {
       INTERRUPTS_OFF
         DetCpfCtl[position].on_off = Active_Wkfile.det_cpf_ctl[position].on_off;
         DetCpfCtl[position].value = Active_Wkfile.det_cpf_ctl[position].value;
         SetDetControlSetpts(DetCpfCtl[position].on_off&DetCpfCtl[position].value,
                                   position );     /* set board */
       INTERRUPTS_ON
      }

   }


}

/***********************************************************************/
/* FUNCTION: InitCPFOIMPresence                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  This functions determines if the CPF's OIM board is       */
/*         present.  OIM loops back all communications to it, this     */
/*         function sends out a pattern and trys to read it back.      */
/*                                                                     */
/* RETURNED VALUE:  None.                                              */
/*                                                                     */
/* LIMITATIONS: EXECUTE ONLY DURING POWERUP - BEFORE 512 IS RUNNING    */
/*                                                                     */
/***********************************************************************/

#define TEST_PATTERN    0x5A

void InitCPFOIMPresence (POSITION pos)
{
   U_INT16 tmpDetSerial;

   tmpDetSerial = DetSerial[pos];

   DetSerial[pos] = TEST_PATTERN;
   DetectorIOTransfer();

   if(pos == FRONT)
   {
      OIMPresence[FRONT] = (FDetSerialIn == TEST_PATTERN) ? TRUE : FALSE;
   }
   else
   {
      OIMPresence[BACK] = (BDetSerialIn == TEST_PATTERN) ? TRUE : FALSE;
   }

   DetSerial[pos] = tmpDetSerial;
}


/***********************************************************************/
/* FUNCTION: CheckCPFDetConfigInWkfile                                 */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  This functions checks the method configuration against    */
/*         the actual configuration and issues an exception for a      */
/*         mismatch.                                                   */
/*                                                                     */
/* RETURNED VALUE:  None.                                              */
/*                                                                     */
/***********************************************************************/

void CheckCPFDetConfigInWkfile(void)
{
   POSITION          pos;
   int              chan;
   BIT8             gas_num;
   BIT8             oem;
   pDETECTOR_STATUS status;

   status = &Inst_Status.Pneu.Frnt_Detector ; /* this is prep for 1st  pass through this loop */

   for (pos = FRONT; (U_INT16)pos < 2; pos = (POSITION)((U_INT16)pos + 1) )
   {
      /* check for detector title presence mismatch */

      oem = ( GetDetType( status ) == EPC_OEM )
            &&
            ( ( GetDetectorType(pos) == OEM_AIB) || ( GetDetectorType(pos) == OEM_FID) );

      if ( (GetCPFDetTitlePresence(pos) || oem ) != gccw.CPFDetTitlePresence[pos])
      {
            /* set exception */
            SetNewException((pos == FRONT) ? F_CPF_DET_TITLE_MISMATCH :
                                       B_CPF_DET_TITLE_MISMATCH, 0, 0);
      }
      else
      {
         if( (oem == 0) && GetCPFDetTitlePresence(pos)) /* check for detector title content mismatch */
         {
            if ((StrLen(GetCPFDetTitle(pos))!=StrLen(gccw.CPFDetTitle[pos])) ||
                (StrNCmp(GetCPFDetTitle(pos), gccw.CPFDetTitle[pos],
                         StrLen(gccw.CPFDetTitle[pos])) != 1))
            {
               /* set exception */
               SetNewException((pos == FRONT) ? F_CPF_DET_TITLE_MISMATCH :
                                            B_CPF_DET_TITLE_MISMATCH, 0, 0);
            }
            else
            {
               ClearNewException((pos == FRONT) ? F_CPF_DET_TITLE_MISMATCH :
                                              B_CPF_DET_TITLE_MISMATCH);
            }
         }
         else
         {
            ClearNewException((pos == FRONT) ? F_CPF_DET_TITLE_MISMATCH :
                                           B_CPF_DET_TITLE_MISMATCH);
         }
      }

      /* check for detector CPF Pneumatics mismatch */
      if(GetCPFDetPneuPresence(pos) != gccw.CPFDetPneuPresence[pos])
      {
            /* set exception */
            SetNewException((pos == FRONT) ? FRNT_DET_TYPE_MISMATCH :
                                       BACK_DET_TYPE_MISMATCH, 0, 0);
      }

      if(  GetCPFDetPneuPresence(pos)  )
      {
         /* check for detector gas presence mismatch */
         for( gas_num = 1; gas_num <= 3 ; gas_num++ )
         {
            if(GetCPFDetGasPresence(pos,gas_num) !=
                                          gccw.CPFDetGasPresence[pos][gas_num])
            {
               /* set exception */
               SetNewException((pos == FRONT) ? FRNT_DET_TYPE_MISMATCH :
                                       BACK_DET_TYPE_MISMATCH, 0, 0);
            }
         }
      }

      /* check for OIM presence mismatch */
      if(GetCPFOIMPresence(pos) != gccw.CPFOIMPresence[pos])
      {
            /* set exception */
            SetNewException((pos == FRONT) ? FRNT_DET_TYPE_MISMATCH :
                                       BACK_DET_TYPE_MISMATCH, 0, 0);
      }

      /* check if number of control bits match for OIM */
      if(GetCPFOIMPresence(pos) == TRUE)
      {
         for( chan = 1; chan <= NUM_OIM_CHAN; chan++)
         {
            if(GetCPFCtlNumBits(pos,chan) != gccw.CPFCtlNumBits[pos][chan])
            {
               /* set exception */
               SetNewException((pos == FRONT) ? FRNT_DET_TYPE_MISMATCH :
                                       BACK_DET_TYPE_MISMATCH, 0, 0);
            }
         }
      }
   status = &Inst_Status.Pneu.Back_Detector ; /* this is prep for 2nd & last pass through this loop */
   }
}

UI_ERR SetRTTOEMCtlOnOff( POSITION position, BIT8 channel, ON_OFF value, BIT8 wkf_flag )
{
   UI_ERR  error;
   U_INT16 mask;

   error = CheckOEMCtlOnOff(position, channel, value );
   if (error == OK)
   {
      mask = 1 << (channel-1);

      if (value == OFF)
      {
          /* reset proper bits */
          INTERRUPTS_OFF

          if (wkf_flag)
          {
             Active_Wkfile.det_cpf_ctl[position].on_off =
              Active_Wkfile.det_cpf_ctl[position].on_off & ~mask; /* set wkfile */
          }

          SetOEMDetInput(position,value,channel) ; /* reset h/w & optional timer */

          INTERRUPTS_ON

      }
      else
      {
          /* value = ON, so turn on bits */

         INTERRUPTS_OFF

         if (wkf_flag)
         {
             Active_Wkfile.det_cpf_ctl[position].on_off =
              Active_Wkfile.det_cpf_ctl[position].on_off | mask; /* set wkfile */
         }

         SetOEMDetInput(position,value,channel) ; /* reset h/w & optional timer */

         INTERRUPTS_ON

      };
   };
   return error;
}

UI_ERR SetOEMCtlOnOff( POSITION position, BIT8 channel, ON_OFF value )
{
   UI_ERR  error;
   BIT8   *label;

   error = SetRTTOEMCtlOnOff( position, channel,  value ,1 );

   if ( (error == NOT_ALLOWED) && value == OFF ) return OK ;  /* off for inactive ctl is ok */
   if (error == OK)
   {
      label = GetCPFCtlLabel(position,channel);

      if (value == OFF)
      {
              /* log setpoint change and set parameter modified flag */
              if (position==FRONT)
              {
                  LogSetptChange(F_DET_CONTROL_OFF,(INT32)label,0);
              }
              else
              {
                 LogSetptChange(B_DET_CONTROL_OFF,(INT32)label,0);
              }
      }
      else
      {
             /* log setpoint change and set parameter modified flag */
             (position==FRONT) ? LogSetptChange(F_DET_CONTROL_ON,(INT32)label,0) :
                             LogSetptChange(B_DET_CONTROL_ON,(INT32)label,0);
      }
   };
   return error;
}

void CheckOEMDetConfigInWkfile(void)
{
   POSITION pos;
   int channl;
   BIT8 gas_num;
   U_INT32 errs[2];

   for (pos = FRONT; (U_INT16)pos < 2; pos = (POSITION)((U_INT16)pos + 1) )
   {
    errs[(BIT8)pos] = 0;

    switch  ( gccw.DetectorType[(BIT8)pos])
    {
       case OEM_AIB:
       case OEM_FID:
            if ( (pos==FRONT) ? DetectorA_Config.host_model :
                          DetectorB_Config.host_model == TYPE_13_14_AS_IS  )
            {
               for( gas_num = 1; gas_num <= LAST_OEM_GAS ; gas_num++ )
               {
                  if( (INT32) OEMDetFritFlags[pos][gas_num-1] != gccw.OEMDetGasModes[pos][gas_num])
                  {
                     /* set exception */
                     errs[(BIT8)pos] += 1 << (gas_num-1) ;   /* bits 2,1,0 */
                  }
               };

               for( channl  = 1; channl  <= LAST_OEM_CTRL ; channl ++ )
               {
                  /* label presence is bit packed; chnls 1..8 in array[.][0], chnls 9..16 in array[.][1], ... */
                  if (
                       ( (  (gccw.OEMCtlStates[pos][(channl-1) >> 3]) >> (( channl-1) % 8)  ) &  0x01 )
                       !=
                       GetOEMCtlPresence(pos,channl)
                     )
                  {
                     /* set exception */
                     errs[(BIT8)pos] += 1 << (channl+MODZ-1) ;   /* bits 12 ... 3 */
                  }

                  if ( ( channl <= LAST_OEM_ONOFF  ) && ( GetOEMCtlPresence(pos,channl) ) )
                  {
                     if ( gccw.OEMCtlPulseLens[pos][channl-1] != GetOEMCtlPulseLen( pos, channl ) )
                     {
                        /* set exception */
                        errs[(BIT8)pos] += 1 << (channl+MODZ+LBLZ-1 ) ;  /* bits 17 ... 13 */
                     }
                  }
               };

            }
            break;

       default:
               break;
    }

   }

   ClearNewException( OEM_DET_CFG_CHGD );

   if ( (errs[0] != 0 ) || (errs[1] != 0 ) )
   {
      RESET_EXCEPTION_DISPLAY();
      SetNewException( OEM_DET_CFG_CHGD, errs[0], errs[1]  );    /* popup to get args out */
                                                                 /* warning does NOT halt meth ld */
   }                                                             /* warning does NOT halt meth ld */

   if ( (errs[0] != 0 ) )
   {
      SetNewException( F_OEM_DET_CFG_CHGD, 0,0 );                /* scrolling smsg will last */
   }                                                             /* meth_warning DOES halt meth ld */
   else
   {
      ClearNewException( F_OEM_DET_CFG_CHGD );

   };

   if ( (errs[1] != 0 ) )
   {
      SetNewException( B_OEM_DET_CFG_CHGD, 0,0 );                /* scrolling smsg will last */
   }                                                             /* meth_warning DOES halt meth ld */
   else
   {
      ClearNewException( B_OEM_DET_CFG_CHGD );
   };

}
/***********************************************************************/
/* FUNCTION: RTTSetOxMCtl                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  These functions is used by the run table                  */
/*                                                                     */
/* RETURNED VALUE:  None.                                              */
/*                                                                     */
/***********************************************************************/

static UI_ERR SetRTTCPFCtlValue( POSITION position, BIT8 channel, INT32 value );
static UI_ERR SetRTTCPFCtlOnOff( POSITION position, BIT8 channel, ON_OFF value );

static void RTTSetOxMCtl ( POSITION position, BIT8 channel, INT32 value )
{
   if (GetCPFDetPneuPresence(  position )  )
   {

      if( value < 0  )
      {
         /* set ON or OFF*/
         (void) SetRTTCPFCtlOnOff( position, channel, (ON_OFF)(2+value) );
      }
      else
      {
         /* set value */
         (void) SetRTTCPFCtlValue( position, channel, value );
         /* set ON */
         (void) SetRTTCPFCtlOnOff( position, channel, ON );
      }
   }
   else
   {
      if( channel == 7  )
      {
         (void) SetRTTOEMXtrlValue( position,  value, 0  ) ;
      }
      else
      {
         (void) SetRTTOEMCtlOnOff( position, channel,  (ON_OFF)(2+value),0  ) ;

      }
   }
}

void RTTSetCPFCtlFrnt1(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 1, value );
}

void RTTSetCPFCtlFrnt2(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 2, value );
}

void RTTSetCPFCtlFrnt3(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 3, value );
}

void RTTSetCPFCtlFrnt4(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 4, value );
}

void RTTSetOEMCtlFrnt5(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 5, value );
}

void RTTSetOEMCtlFrnt7(INT32 value)
{
   RTTSetOxMCtl ( FRONT, 7, value );
}

void RTTSetCPFCtlBack1(INT32 value)
{
   RTTSetOxMCtl ( BACK, 1, value );
}

void RTTSetCPFCtlBack2(INT32 value)
{
   RTTSetOxMCtl ( BACK, 2, value );
}

void RTTSetCPFCtlBack3(INT32 value)
{
   RTTSetOxMCtl ( BACK, 3, value );
}

void RTTSetCPFCtlBack4(INT32 value)
{
   RTTSetOxMCtl ( BACK, 4, value );
}

void RTTSetOEMCtlBack5(INT32 value)
{
   RTTSetOxMCtl ( BACK, 5, value );
}

void RTTSetOEMCtlBack7(INT32 value)
{
   RTTSetOxMCtl ( BACK, 7, value );
}


/***********************************************************************/
/* FUNCTION: SetRTTCPFCtlOnOff                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Sets ON or OFF parameter in the active value for           */
/*         the given OIM module's control channel.                     */
/*         Used for the Run Table.                                     */
/*                                                                     */
/* RETURNED VALUE:  Error code                                         */
/*                                                                     */
/***********************************************************************/


static UI_ERR SetRTTCPFCtlOnOff( POSITION position, BIT8 channel, ON_OFF value )
{
   UI_ERR  error;
   U_INT16 mask;
   BIT8    shift;
   BIT8    format;

   error = CheckCPFCtlOnOff(position, channel, value );
   if( (error == INVALID_PARAM) && (value == OFF) )
   {
      /* To keep chemstation happy:   */
      /*    this channel is not in use, a value of 0 is allowed */
      /*    but don't do anything. */
      error = OK;
      return error;
   }
   if(error == OK)
   {
      switch ( channel )
      {
         default:
         case 1: mask  = (position==FRONT) ? FDCtl1.mask  : BDCtl1.mask;
                 shift = (position==FRONT) ? FDCtl1.shift : BDCtl1.shift;
                 format =(position==FRONT) ? FDCtl1.format : BDCtl1.format;
                 break;

         case 2: mask  = (position==FRONT) ? FDCtl2.mask  : BDCtl2.mask;
                 shift = (position==FRONT) ? FDCtl2.shift : BDCtl2.shift;
                 format =(position==FRONT) ? FDCtl2.format : BDCtl2.format;
                 break;

         case 3: mask  = (position==FRONT) ? FDCtl3.mask  : BDCtl3.mask;
                 shift = (position==FRONT) ? FDCtl3.shift : BDCtl3.shift;
                 format =(position==FRONT) ? FDCtl3.format : BDCtl3.format;
                 break;

         case 4: mask  = (position==FRONT) ? FDCtl4.mask  : BDCtl4.mask;
                 shift = (position==FRONT) ? FDCtl4.shift : BDCtl4.shift;
                 format =(position==FRONT) ? FDCtl4.format : BDCtl4.format;
                 break;
      }

      if(value == OFF)
      {
          /* reset proper bits */
         INTERRUPTS_OFF
            DetCpfCtl[position].on_off =
               DetCpfCtl[position].on_off & ~mask; /* set working copy */
            SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                      position );     /* set board */
         INTERRUPTS_ON
      }
      else
      {
         /* value = ON, so turn on bits */

         if (format == FRMT_ON_OFF)
         {
            /* make sure value is all 1s for ON_OFF format */
            /*   so bit will come on */
            (void)SetCPFCtlValue( position, channel,
                     (INT32)MaxCPFCtlValue(position,channel) );
         }

         /* Numeric format so set value */

         INTERRUPTS_OFF
         DetCpfCtl[position].on_off =
               (DetCpfCtl[position].on_off & ~mask) |
               ( ((U_INT16)MaxCPFCtlValue(position,channel)<<shift) & mask );  /*set work cpy*/
         SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                      position );     /* set board */
         INTERRUPTS_ON

      }
   }
   return error;
}


/***********************************************************************/
/* FUNCTION: SetRTTCPFCtlValue                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Set the active value for the given OIM module's control    */
/*        channel. Used for Run Table.                                 */
/*                                                                     */
/* RETURNED VALUE:  Error code                                         */
/*                                                                     */
/***********************************************************************/

static UI_ERR SetRTTCPFCtlValue( POSITION position, BIT8 channel, INT32 value )
{
   UI_ERR  error;
   U_INT16 mask;
   BIT8    shift;
   BIT8    format;

   error = CheckCPFCtlValue(position, channel, value );
   if( (error == INVALID_PARAM) && (value == 0) )
   {
      /* To keep chemstation happy:   */
      /*    this channel is not in use, a value of 0 is allowed */
      /*    but don't do anything. */
      error = OK;
      return error;
   }
   if(error == OK)
   {
      switch ( channel )
      {
         default:
         case 1: mask  = (position==FRONT) ? FDCtl1.mask  : BDCtl1.mask;
                 shift = (position==FRONT) ? FDCtl1.shift : BDCtl1.shift;
                 format =(position==FRONT) ? FDCtl1.format : BDCtl1.format;
                 break;

         case 2: mask  = (position==FRONT) ? FDCtl2.mask  : BDCtl2.mask;
                 shift = (position==FRONT) ? FDCtl2.shift : BDCtl2.shift;
                 format =(position==FRONT) ? FDCtl2.format : BDCtl2.format;
                 break;

         case 3: mask  = (position==FRONT) ? FDCtl3.mask  : BDCtl3.mask;
                 shift = (position==FRONT) ? FDCtl3.shift : BDCtl3.shift;
                 format =(position==FRONT) ? FDCtl3.format : BDCtl3.format;
                 break;

         case 4: mask  = (position==FRONT) ? FDCtl4.mask  : BDCtl4.mask;
                 shift = (position==FRONT) ? FDCtl4.shift : BDCtl4.shift;
                 format =(position==FRONT) ? FDCtl4.format : BDCtl4.format;
                 break;
      }

      if(format == FRMT_ON_OFF)
      {
         /* for ON/OFF format always set value to all 1s */
         value = (INT32)MaxCPFCtlValue(position,channel);
      }

      INTERRUPTS_OFF
      DetCpfCtl[position].value =
            (DetCpfCtl[position].value & ~mask) |
            ( (((U_INT16)value)<<shift) & mask );  /* set working copy */
      SetDetControlSetpts( (DetCpfCtl[position].on_off & DetCpfCtl[position].value),
                                   position );     /* set board */
      INTERRUPTS_ON

   }
   return error;
}

/***********************************************************************/
/* FUNCTION:  GetCPFDetUnitsLabelPresence                              */
/* ========                                                            */
/*                                                                     */
/***********************************************************************/

BIT8 GetCPFDetUnitsLabelPresence( POSITION position )
{
   DET_CONFIG *pconfig;

   pconfig = (position==FRONT) ? &DetectorA_Config : &DetectorB_Config;

   return (pconfig->units_label[0]==0) ? FALSE : TRUE;
}

BIT8 *GetCPFDetUnitsLabel( POSITION position )
{
   DET_CONFIG *pconfig;

   pconfig = (position==FRONT) ? &DetectorA_Config : &DetectorB_Config;

   return &(pconfig->units_label[0]);
}

ON_OFF GetOEMOnOffActual( POSITION position, BIT8 channel )
{
   switch (channel)
   {
         default:
         case 1:
            return GetDetInput1(position);
         case 2:
            return GetDetInput2(position);
         case 3:
            return GetDetInput3(position);
         case 4:
            return GetDetInput4(position);
         case 5:
            return GetDetInput5(position);
   }

}

ON_OFF GetOEMCtlOnOff( POSITION position, BIT8 channel )
{
#if 0
{
   switch (channel)
   {
         default:
         case 1:
            return GetDetInput1(position);
         case 2:
            return GetDetInput2(position);
         case 3:
            return GetDetInput3(position);
         case 4:
            return GetDetInput4(position);
         case 5:
            return GetDetInput5(position);
   }
}
#endif

   U_INT16 mask;

   mask = 1 << (channel-1);

   return (Active_Wkfile.det_cpf_ctl[position].on_off & mask) == 0  ? OFF : ON ;
}

BIT8 GetOEMCtlPulseLen( POSITION position, BIT8 channel )
{
   switch ( channel )
   {
      default:
      case 1:
              return (position==FRONT) ? FDCtl1.pulse_len : BDCtl1.pulse_len;
      case 2:
              return (position==FRONT) ? FDCtl2.pulse_len : BDCtl2.pulse_len;
      case 3:
              return (position==FRONT) ? FDCtl3.pulse_len : BDCtl3.pulse_len;
      case 4:
              return (position==FRONT) ? FDCtl4.pulse_len : BDCtl4.pulse_len;
      case 5:
              return (position==FRONT) ? FDCtrl5.pulse_len : BDCtrl5.pulse_len;
   }
}


void SetOEMDetInput(POSITION p, ON_OFF on_off, BIT8 channl )
{
   BIT8   puls_len;
   BIT8           *pulse;

   puls_len = (on_off == ON) ? GetOEMCtlPulseLen( p, channl ) : 0 ;

   switch ( channl )
   {
      default:
      case 1:
              SetDetInput1(p, on_off);
              pulse = (p == FRONT)? &FDCtl1.pulse_left: &BDCtl1.pulse_left  ;
              break ;
      case 2:
              SetDetInput2(p, on_off);
              pulse = (p == FRONT)? &FDCtl2.pulse_left: &BDCtl2.pulse_left  ;
              break ;
      case 3:
              SetDetInput3(p, on_off);
              pulse = (p == FRONT)? &FDCtl3.pulse_left: &BDCtl3.pulse_left  ;
              break ;
      case 4:
              SetDetInput4(p, on_off);
              pulse = (p == FRONT)? &FDCtl4.pulse_left: &BDCtl4.pulse_left  ;
              break ;
      case 5:
              SetDetInput5(p, on_off);
              pulse = (p == FRONT)? &FDCtrl5.pulse_left: &BDCtrl5.pulse_left  ;
              break ;
   }
   *pulse = puls_len ;
}


UI_ERR CheckOEMXtlValue( POSITION position, INT32 value )
{
   if ( GetOEMCtlPresence( position,7 ) == FALSE  )
   {
      return NOT_ALLOWED;
   }

   if ( value < 0 )  return PARAM_TOO_SMALL;

   if ( value > 65535  )  return PARAM_TOO_LARGE ;

   return OK;
}

static UI_ERR SetRTTOEMXtrlValue( POSITION position,  INT32 value , BIT8 wkf_flag )
{
   UI_ERR  error;

   error = CheckOEMXtlValue(position,  value );

   if(error == OK)
   {
     if( (value==65535) && ( OEMPollTym[(BIT8)position] != 0 )) return PARAM_TOO_LARGE ;

     INTERRUPTS_OFF

     if (wkf_flag)
     {
        Active_Wkfile.det_cpf_ctl[position].value = value ;
     };

     DetSerial[ (position == FRONT)? 0:1] =  value ;

     INTERRUPTS_ON

   }

   return error;
}

UI_ERR SetOEMXtrlValue( POSITION position,  INT32 value )
{
   UI_ERR  error;
   BIT8   *label;

   error = SetRTTOEMXtrlValue( position,   value, 1 );
   if ( (error == NOT_ALLOWED) && value == 0 ) return OK ;  /* off for inactive ctl is ok */

   label = GetCPFCtlLabel(position,7);

   if(error != OK) return error;

   if (position==FRONT)
   {
      LogSetptChange(F_DET_CONTROL,(INT32)label,value);
   }
   else
   {
      LogSetptChange(B_DET_CONTROL,(INT32)label,value);
   }

   return OK;
}
